import java.awt.*;
import java.util.*;
import java.awt.event.*;
import javax.swing.event.MouseInputAdapter;
import javax.swing.JOptionPane;

public class GUI extends Frame {
    Image img;
    Image agents[] = new Image[6];
    Point agentPositions[] = new Point[6];
    /** The x-position of the map image*/
    int x;
    /** The y-position of the map image*/
    int y;
    int imageWidth;
    int imageHeight;
    int borderSize;
    MediaTracker mt;
    Map map;
    Set<Node> availableNodes;
    ScotlandYard game;
    int clickedAgent;
    Node clickedNode;
    int clickedTransport;



    public GUI(Map mapIn, ScotlandYard gameIn){
        super("Image Frame");
        map = mapIn;
        game = gameIn;
        imageWidth = 1280;
        imageHeight = 980;
        this.addKeyListener(new MyKeyListener());
        MyMouseListener mouse = new MyMouseListener();
        this.addMouseMotionListener(mouse);
        this.addMouseListener(mouse);
        mt = new MediaTracker(this);
        img = Toolkit.getDefaultToolkit().getImage("../data/map.jpg");
        mt.addImage(img,2);
        for (int i = 0; i < 5; i++) {
            agents[i] = Toolkit.getDefaultToolkit().getImage("../data/detective"+i+".png");
            mt.addImage(agents[i], 1);
            placeAgent(i, map.agents[i].getPosition());
        }
        agents[5] = Toolkit.getDefaultToolkit().getImage("../data/mrx.png");
        agentPositions[5] = new Point(map.agents[5].getPosition().getMapPosition());
        agentPositions[5].translate(-25, -25);
        mt.addImage(agents[5],1);
        setSize(800, 600);
        setVisible(true);
        addWindowListener(new WindowAdapter(){
                public void windowClosing(WindowEvent we){
                dispose();
                }
                });
        borderSize = getInsets().top;
        x = borderSize;
        y = 0;
    }

    public void update(Graphics g){
        paint(g);
    }

    public void paint(Graphics g){
        if(img != null)
            g.drawImage(img, x, y, this);
        else
            g.clearRect(0, 0, getSize().width, getSize().height);

        for(int i=0;i<6;i++)
        {
            if(agentPositions[i] != null && agents[i] != null)
                g.drawImage(agents[i], agentPositions[i].x,agentPositions[i].y, this);
        }
    }



    //TODO: On resize, make it repaint
    //FIXME: If you move the map too fast, the agents get slightly misplaced...
    public void move_screen(int dx, int dy) {
        x += dx;
        y += dy;

        // Don't move out of the image
        if (x > 0) {
            x = 0;
        } else if (x < (getSize().width - imageWidth))
        {
            x = getSize().width - imageWidth;
        }/* else
        {
            for (int i=0;i<6;i++)
            {
                agentPositions[i].translate(dx, 0);
            }
        }*/
        
        if (y > borderSize) {
            y = borderSize;
        } else if (y < (getSize().height - imageHeight)) {
            y = getSize().height - imageHeight;
        } /*else {
            for (int i=0;i<6;i++)
            {
                agentPositions[i].translate(0,dy);
            }
        }*/
        for(int i=0;i<6;i++)
        {
            placeAgent(i);
        }
        repaint();
    }

    public void placeAgent(int agentIndex)
    {
        agentPositions[agentIndex] = new Point(map.agents[agentIndex].getPosition().getMapPosition());
        agentPositions[agentIndex].translate(x -25,y -25);
    }

    /**
     * Place the agent on a certain spot in the map.
     * It is done in such a way that the agent is on the right screen position.
     */
    public void placeAgent(int agentIndex, Node position)
    {
        agentPositions[agentIndex] = new Point(position.getMapPosition());
        // Put the centre on the node
        agentPositions[agentIndex].translate(x -25,y -25);
    }

    

    /**
     * Move the agent to another node. Goes further in moveAgent2
     * @return the clicked agent
     */
    public void moveAgent1(int identifier)
    {
        //get a list of available positions
        availableNodes = map.agents[identifier].getPosition().connectedNodes();
        System.out.print("You can go to: \n");
        for (Node node : availableNodes)
        {
            System.out.printf("%d\n", node.getNum());
        }
        System.out.println("Click one.");


    }

    /**
     * used if an agent was clicked to move to another node
     * @return: the node to which the agent was moved
     */
    public Node moveAgent2(int identifier, Point clicked)
    {
        //get a list of available traffic
        Node clickedNode = map.getClosestNode(clicked, availableNodes); 
        System.out.printf("This node was clicked: %d\n", clickedNode.getNum());
        Set<Integer> waysConnectedSet = map.agents[identifier].getPosition().waysConnected(clickedNode);
        Integer[] waysConnected = waysConnectedSet.toArray(new Integer[waysConnectedSet.size()]);

        //Custom button text
        String[] options = {"Taxi (" + map.agents[identifier].getNumberOfTickets(0) + ")",
                            "Bus (" + map.agents[identifier].getNumberOfTickets(1) + ")",
                            "Underground (" + map.agents[identifier].getNumberOfTickets(2) + ")"};
        String[] trueOptions = new String[waysConnected.length];
        for (int i=0;i<waysConnected.length;i++)
        {
            trueOptions[i] = options[waysConnected[i]];
        }

        //move to the other position.
        int clickedTransport = JOptionPane.showOptionDialog(this,
            "Choose your type of transport to node " + clickedNode.getNum(), // Message
            "Transport", //Name of dialog
            JOptionPane.YES_NO_CANCEL_OPTION, //Option type
            JOptionPane.QUESTION_MESSAGE, //Message type
            null, //The icon is only a concept in your mind!
            trueOptions, // Possible options
            null); // default
        if(clickedTransport == -1)
            return null;
        try {
            game.move(identifier, new Movement(clickedNode, clickedTransport));
        } catch (Exception e) {
            // Agent has already moved
            System.out.println(e.getMessage());
            System.out.printf("Returning to node, %d", map.agents[identifier].getPosition().getNum());
            return null;
        }
        return clickedNode;
    }

    /**
     * Asks the user if you want to play another game
     * @return: 0 if yes, 1 if no, -1 if cancelled
     */
    public int win()
    {
        String[] options = {"Yes", "No"};
        int answer = JOptionPane.showOptionDialog(this,
            "Congratulations, you have found Mr X. \n Do you want to play another game?", // Message
            "You won!", //Name of dialog
            JOptionPane.YES_NO_CANCEL_OPTION, //Option type
            JOptionPane.QUESTION_MESSAGE, //Message type
            null, //The icon is only a concept in your mind!
            options, // Possible options
            null); // default
        return answer;
    }

    /**
     * Asks the user if you want to play another game
     * @return: 0 if yes, 1 if no, -1 if cancelled
     */
    public int lose()
    {
        String[] options = {"Yes", "No"};
        int answer = JOptionPane.showOptionDialog(this,
            "Too bad. Mr X. has escaped from your search team. \n Do you want to play another game?", // Message
            "You lost! :-(", //Name of dialog
            JOptionPane.YES_NO_CANCEL_OPTION, //Option type
            JOptionPane.QUESTION_MESSAGE, //Message type
            null, //The icon is only a concept in your mind!
            options, // Possible options
            null); // default
        return answer;
    }

    public class MyKeyListener extends KeyAdapter {
        public void keyPressed(KeyEvent ke) {
            switch (ke.getKeyCode()) {
                case KeyEvent.VK_UP:
                    move_screen(0, 10);
                    break;
                case KeyEvent.VK_DOWN:
                    move_screen(0, -10);
                    break;
                case KeyEvent.VK_LEFT:
                    move_screen(10, 0);
                    break;
                case KeyEvent.VK_RIGHT:
                    move_screen(-10, 0);
                    break;
            }
        }
    }

    public class MyMouseListener extends MouseInputAdapter
    {
        int clickedAgent;
        Point oldPos;
        Boolean clickingAgents = true;

        public void mouseClicked(MouseEvent e)
		{
            Point clicked = e.getPoint();
            clicked.translate(-x, -y);
            if(clickingAgents)
            {
                clickedAgent = map.getClosestAgent(clicked);
                clickingAgents = false;
                moveAgent1(clickedAgent);
                System.out.printf("Agent clicked: %d on: %s\n", clickedAgent, agentPositions[clickedAgent]);
            }
            else
            {
                Object[] a = new Object[2];
                Node newPosition = moveAgent2(clickedAgent, clicked);
                if (newPosition == null)
                {
                    System.out.println("Move canceled");
                    clickingAgents = true;
                    return;
                }
                System.out.println("Moved");
                //update the local position variable
                placeAgent(clickedAgent, newPosition);
                //repaint, to see the new position of the moved agent
                repaint();
                clickingAgents = true;
            }
        }

        public void mousePressed(MouseEvent e)
        {
            oldPos = e.getPoint();
        }

        public void mouseDragged(MouseEvent e)
        {
            move_screen((int) (e.getX() - oldPos.getX()) , (int) (
                        e.getY() - oldPos.getY()));
            oldPos = e.getPoint();
        }
    }
}
